<?php

require_once(t3lib_extMgm::extPath('zlib') . 'class.tx_zlib_gateway.php');
require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_categories.php');
require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_forums.php');
require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_topics.php');
require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_replies.php');
require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_posts.php');


class tx_zboard_gateway extends tx_zlib_gateway
{

    /**
     * @var string
     */
    private $authorField = 'username';

    /**
     * @return string
     */
    public function getAuthorField()
    {
        return $this->authorField;
    }

    /**
     * @param string $field
     */
    public function setAuthorField($field)
    {
        $this->authorField = $field;
    }

    /**
     * @param integer $profileId
     * @return tx_zboard_profile
     */
    public function fetchProfile($profileId)
    {
        $authorField = $this->getAuthorField();
        $where  = "fe_users.uid=$profileId";
        $where .= $this->enableFields('fe_users');
        $rows = $this->_db->exec_SELECTgetRows(
            "*, $authorField AS author",
            'fe_users',
            $where
        );
        if(isset($rows[0])) {
            unset($rows[0]['password']);
        }
        require_once(t3lib_extMgm::extPath('zboard') . 'class.tx_zboard_profile.php');
        return isset($rows[0]) ? new tx_zboard_profile($rows[0]) : null;
    }

    /**
     * @param integer $pid
     * @param string $subject
     * @param string $message
     * @param integer $feUserUid
     * @param integer $notifyMe
     */
    public function insertTopic($pid, $subject, $message, $feUserUid, $notifyMe)
    {
        $time = time();
        $data = array(
            'pid' => $pid,
            'subject' => strip_tags($subject),
            'message' => strip_tags($message),
            'tstamp' => $time,
            'crdate' => $time,
            'reply_count' => 0,
            'user_id' => $feUserUid,
            'last_post_tstamp' => $time,
            'last_post_user_id' => $feUserUid,
            'notify_me' => $notifyMe
        );

        $this->_db->exec_INSERTquery(
            'tx_zboard_topics',
            $data
        );

        $this->updateFeuserPostCount($feUserUid);
        $this->updatePage($pid, $feUserUid, $time);

    }

    /**
     * @param integer $pid
     * @param string $subject
     * @param string $message
     * @param integer $topicId
     * @param integer $feUserUid
     */
    public function insertReply($pid, $subject, $message, $topicId, $feUserUid)
    {
        $time = time();
        $data = array(
            'pid' => $pid,
            'topic_id' => $topicId,
            'subject' => strip_tags($subject),
            'message' => strip_tags($message),
            'tstamp' => $time,
            'crdate' => $time,
            'user_id' => $feUserUid
        );
        $this->_db->exec_INSERTquery(
            'tx_zboard_replies',
            $data
        );

        $replyCount = $this->countRepliesByTopicId($topicId);

        // Topic aktualisieren
        $data = array(
            'reply_count' => $replyCount,
            'last_post_tstamp' => $time,
            'last_post_user_id' => $feUserUid
        );
        $this->_db->exec_UPDATEquery(
            'tx_zboard_topics',
            "uid=$topicId",
            $data
        );

        $this->updateFeuserPostCount($feUserUid);
        $this->updatePage($pid, $feUserUid, $time);

    }

    /**
     * @param integer $topicId
     * @return integer
     */
    public function countRepliesByTopicId($topicId)
    {
        $rows = $this->_db->exec_SELECTgetRows(
            'count(uid) AS count',
            'tx_zboard_replies',
            "topic_id=$topicId" . $this->enableFields('tx_zboard_replies')
        );
        return isset($rows[0]) ? $rows[0]['count'] : 0;
    }

    /**
     * @param integer $feuserId
     * @return integer
     */
    public function countPostsByFeuser($feuserId)
    {
        $topics = $this->countTopicsByFeuser($feuserId);
        $replies = $this->countRepliesByFeuser($feuserId);
        return $topics + $replies;
    }

    /**
     * @param integer $feuserId
     * @return integer
     */
    public function countTopicsByFeuser($feuserId)
    {
        $rows = $this->_db->exec_SELECTgetRows(
            'count(uid) AS count',
            'tx_zboard_topics',
            "user_id=$feuserId" . $this->enableFields('tx_zboard_topics')
        );
        return isset($rows[0]) ? intval($rows[0]['count']) : 0;
    }

    /**
     * @param integer $feuserId
     * @return integer
     */
    public function countRepliesByFeuser($feuserId)
    {
        $rows = $this->_db->exec_SELECTgetRows(
            'count(uid) AS count',
            'tx_zboard_replies',
            "user_id=$feuserId" . $this->enableFields('tx_zboard_replies')
        );
        return isset($rows[0]) ? intval($rows[0]['count']) : 0;
    }

    /**
     * @param boolean $returnCollection
     * @return tx_zboard_topics
     */
    public function fetchTopics($returnCollection = true)
    {
        $pid = $this->getPageId();
        $authorField = $this->getAuthorField();
        $where  = "tx_zboard_topics.pid=$pid";
        $where .= $this->enableFields('tx_zboard_topics');
        $rows = $this->_db->exec_SELECTgetRows(
            "tx_zboard_topics.*, fu1.$authorField AS author, fu2.$authorField AS last_post_author",
            'tx_zboard_topics
                LEFT JOIN fe_users AS fu1 ON fu1.uid = tx_zboard_topics.user_id
                LEFT JOIN fe_users AS fu2 ON fu2.uid = tx_zboard_topics.last_post_user_id',
            $where,
            '', // group by
            'last_post_tstamp DESC' // order by
        );
        return $returnCollection ? new tx_zboard_topics($rows) : $rows;
    }

    /**
     * @param integer $topicId
     * @param boolean $returnCollection
     * @return tx_zboard_topics
     */
    public function fetchReplies($topicId, $returnCollection = true)
    {
        $where  = "tx_zboard_replies.topic_id=$topicId";
        $where .= $this->enableFields('tx_zboard_replies');
        $authorField = $this->getAuthorField();
        $rows = $this->_db->exec_SELECTgetRows(
            "tx_zboard_replies.*, fe_users.$authorField AS author, fe_users.crdate AS joined_tstamp, (fe_users.tx_zboard_topic_count + fe_users.tx_zboard_reply_count) AS post_count, fe_users.tx_zboard_topic_count AS topic_count, fe_users.tx_zboard_reply_count AS reply_count, fe_users.image AS avatar",
            'tx_zboard_replies LEFT JOIN fe_users ON fe_users.uid = tx_zboard_replies.user_id',
            $where,
            '', // group by
            'tx_zboard_replies.crdate ASC' // order by
        );
        return $returnCollection ? new tx_zboard_replies($rows) : $rows;
    }

    /**
     * @return tx_zboard_categories
     */
    public function fetchCategories()
    {
        $pages = $GLOBALS['TSFE']->sys_page->getMenu(
            $this->getPageId(),
            'uid, title, subtitle, tx_zboard_topic_count AS topic_count, (tx_zboard_topic_count + tx_zboard_reply_count) AS post_count, tx_zboard_topic_count AS topic_count, tx_zboard_reply_count AS reply_count, tx_zboard_last_post_tstamp AS last_post, tx_zboard_last_post_user_id AS last_post_user_id',
            'sorting',
            ' AND nav_hide=0'
        );
        foreach($pages AS $index=>$page) {
            $pages[$index]['forums'] = $this->fetchForums($page['uid'], 'array');
        }

        return new tx_zboard_categories($pages);
    }

    /**
     * Call by reference
     *
     * @param array $pages
     */
    private function addFeuserInfo(array &$pages)
    {
        $pageIds = array();
        foreach($pages AS $page) {
            $pageIds[] = $page['uid'];
        }
        if(count($pageIds) > 0) {
            $authorField = $this->getAuthorField();
            $rows = $this->_db->exec_SELECTgetRows(
                "pages.uid, fe_users.uid AS user_id, fe_users.$authorField AS author, (fe_users.tx_zboard_topic_count + fe_users.tx_zboard_reply_count) AS author_post_count",
                'pages LEFT JOIN fe_users ON fe_users.uid = pages.tx_zboard_last_post_user_id' . $this->enableFields('fe_users'),
                'pages.uid IN (' . implode(',', $pageIds) . ')' . $this->enableFields('pages')
            );            
            foreach($rows AS $row) {
                $uid = $row['uid'];
                $author = '';
                if(isset($pages[$uid])) {
                    $author = $row['author'];
                }
                $pages[$uid]['last_post_author'] = $author;
                $pages[$uid]['author_post_count'] = $row['author_post_count'];
            }
        }
    }

    /**
     * @param array $pageIds
     * @return array
     */
    public function countTopicsByPageIds(array $pageIds)
    {
        $rows = array();
        if(count($pageIds) > 0) {
            $where .= 'pages.uid IN (' . implode(',', $pageIds) . ')';
            $where .= $this->enableFields('pages');
            $where .= $this->enableFields('tx_zboard_topics');

            $resource = $this->_db->exec_SELECTquery(
                'count(tx_zboard_topics.uid) AS count, pages.uid AS pid',
                'tx_zboard_topics INNER JOIN pages ON pages.uid = tx_zboard_topics.pid',
                $where,
                'pages.uid'
            );

            while($row = $this->_db->sql_fetch_assoc($resource)) {
                $pid = $row['pid'];
                $count = $row['count'];
                $rows[$pid] = $count;
            }
            return $rows;
        }
    }

    /**
     * @param integer $id
     * @return integer
     */
    public function countTopicsByPageId($id)
    {
        $rows = $this->countTopicsByPageIds(array($id));
        return !empty($rows[$id]) ? $rows[$id] : 0;
    }

    /**
     * @param array $pageIds
     * @return array
     */
    public function countRepliesByPageIds(array $pageIds)
    {
        $rows = array();
        if(count($pageIds) > 0) {
            $where .= 'pages.uid IN (' . implode(',', $pageIds) . ')';
            $where .= $this->enableFields('pages');
            $where .= $this->enableFields('tx_zboard_replies');

            $resource = $this->_db->exec_SELECTquery(
                'count(tx_zboard_replies.uid) AS count, pages.uid AS pid',
                'tx_zboard_replies INNER JOIN pages ON pages.uid = tx_zboard_replies.pid',
                $where,
                'pages.uid'
            );

            while($row = $this->_db->sql_fetch_assoc($resource)) {
                $pid = $row['pid'];
                $count = $row['count'];
                $rows[$pid] = $count;
            }
            return $rows;
        }
    }

    /**
     * @param integer $id
     * @return integer
     */
    public function countRepliesByPageId($id)
    {
        $rows = $this->countRepliesByPageIds(array($id));
        return !empty($rows[$id]) ? $rows[$id] : 0;
    }

    /**
     * @param integer $pageId
     * @param string $returnType
     * @return tx_zboard_forums|array
     */
    public function fetchForums($pageId = 0, $returnType = 'collection')
    {
        $pageId = empty($pageId) ? $this->getPageId() : $pageId ;
        $forums = $GLOBALS['TSFE']->sys_page->getMenu(
            $pageId,
            'uid, title, subtitle, (tx_zboard_topic_count + tx_zboard_reply_count) AS post_count, tx_zboard_topic_count AS topic_count, tx_zboard_reply_count AS reply_count, tx_zboard_last_post_tstamp AS last_post, tx_zboard_last_post_user_id AS last_post_user_id',
            'sorting',
            ' AND nav_hide=0'
        );

        $this->addFeuserInfo($forums);

        if($returnType === 'collection') {
            return new tx_zboard_forums($forums);
        }
        return $forums;
    }

    /**
     * @param integer $topicId
     * @return tx_zboard_topic
     */
    public function fetchTopic($topicId)
    {
        $authorField = $this->getAuthorField();
        $where  = "tx_zboard_topics.uid=$topicId";
        $where .= $this->enableFields('tx_zboard_topics');
        $rows = $this->_db->exec_SELECTgetRows(
            "tx_zboard_topics.*, fe_users.$authorField AS author, fe_users.email, fe_users.crdate AS joined_tstamp, (fe_users.tx_zboard_topic_count + fe_users.tx_zboard_reply_count) AS post_count, fe_users.image AS avatar",
            'tx_zboard_topics LEFT JOIN fe_users ON fe_users.uid = tx_zboard_topics.user_id' . $this->enableFields('fe_users'),
            $where,
            '', // group by
            'crdate DESC' // order by
        );
        return isset($rows[0]) ? new tx_zboard_topic($rows[0]) : null;
    }

    /**
     * @param integer $rootPid
     * @param integer $pageId
     * @return array
     */
    public function fetchRootline($rootPid = 0, $pageId = 0)
    {
        if(empty($pageId)) {
            $pageId = $this->getPageId();
        }
        $rootline = $GLOBALS['TSFE']->sys_page->getRootline($pageId);
        // Alle Seiten ab ROOT entfernen
        if($rootPid > 0) {
            $unset = false;
            foreach($rootline AS $index=>$page) {
                if($unset) {
                    unset($rootline[$index]);
                }
                if($page['uid'] == $rootPid) {
                    $unset = true;
                }
            }
        }
        return array_reverse($rootline);
    }

    /**
     * @param integer $topicId
     * @param boolean $returnCollection
     * @return unknown
     */
    public function fetchPosts($topicId, $returnCollection = true)
    {
        $posts = array();
        $topicObj = $this->fetchTopic($topicId);
        if($topicObj instanceof tx_zboard_topic) {
            $posts = $this->fetchReplies($topicId, false);
            array_unshift($posts, $topicObj->toArray());
        }
        return $returnCollection ? new tx_zboard_posts($posts) : $posts;
    }

    /**
     * @param integer $pageId
     * @param integer $feUserUid
     * @param integer $time
     */
    private function updatePage($pageId, $feUserUid, $time)
    {
        $data = array(
            'tx_zboard_last_post_user_id' => $feUserUid,
            'tx_zboard_last_post_tstamp' => $time,
            'tx_zboard_topic_count' => $this->countTopicsByPageId($pageId),
            'tx_zboard_reply_count' => $this->countRepliesByPageId($pageId)
        );

        $this->_db->exec_UPDATEquery(
            'pages',
            "uid=$pageId",
            $data
        );

        $this->deletePageCache($pageId);
    }

    /**
     * @param integer $pageId
     */
    private function deletePageCache($pageId)
    {
        $rootline = $this->fetchRootline($pageId);
        foreach($rootline AS $page) {
            $this->_db->exec_DELETEquery('cache_pages', 'page_id=' . $page['uid']);
            $this->_db->exec_DELETEquery('cache_pagesection', 'page_id=' . $page['uid']);
        }
    }

    /**
     * @param integer $feuserId
     */
    private function updateFeuserPostCount($feuserId)
    {
        $data = array(
            'tx_zboard_topic_count' => $this->countPostsByFeuser($feuserId),
            'tx_zboard_reply_count' => $this->countRepliesByFeuser($feuserId),
        );
        $this->_db->exec_UPDATEquery(
            'fe_users',
            "uid=$feuserId",
            $data
        );
    }

}

if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/zboard/class.tx_zboard_gateway.php']) {
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/zboard/class.tx_zboard_gateway.php']);
}
